import {
  PatchState,
  type Plugin,
  type PluginKey,
  type Transaction,
} from "@rivet/state";
import type {
  EditorEvents,
  EditorOptions,
  JSONContent,
  SingleCommands,
  SingleSelectors,
} from "./types.ts";
import { EventEmitter } from "./EventEmitter.ts";
import type { MarkType, Node, NodeType, Schema } from "@rivet/model";
import { ExtensionManager } from "./ExtensionManager.ts";
import { immer } from "@rivet/state";
import { isFunction } from "./utilities/isFunction.ts";
import { getAttributes } from "./helpers/getAttributes.ts";
import { type History, HistoryManager } from "./HistoryManager.ts";
import { CommandManager } from "./CommandManager.ts";
import { SelectorManager } from "./SelectorsManager.ts";
const { enableMapSet, enablePatches } = immer;

/*
 rivet 编辑器核心实现
 1. 状态管理PatchState
    更改状态，并记录状态，统一入口
 2. 命令管理CommandManager
    构建命令，并绑定到编辑器，可构建最基础的操作，比如增删改
 3. 选择器管理SelectorManager
    构建查询，并绑定到编辑器，主要是添加查询缓存 基础库使用reselect
 4. 历史记录管理HistoryManager
    依赖状态管理，并记录状态，支持前进后退
 5. 扩展管理器ExtensionManager
    构建扩展，并绑定到编辑器，功能可以按扩展的方式进行添加，并可以在扩展中添加自己的命令，选择器，插件
*/
export class Editor extends EventEmitter<EditorEvents> {
  public state!: PatchState;
  public schema!: Schema;
  private commandManager!: CommandManager;
  private selectorManager!: SelectorManager;
  public extensionManager!: ExtensionManager;
  public historyManager!: HistoryManager;
  public extensionStorage: Record<string, any> = {};
  public options: EditorOptions = {
    onBeforeCreate: () => null,
    onCreate: () => null,
    onUpdate: () => null,
    onTransaction: () => null,
    onDestroy: () => null,
    extensions: [],
    content: function (_schema: Schema): Node {
      throw new Error("Function not implemented.");
    },
    historyLimit: 5,
    lruMaxSize: 10,
  };

  // 初始化编辑器
  constructor(options: Partial<EditorOptions> = {}) {
    super();
    enableMapSet();
    enablePatches();
    //设置操作参数
    this.setOptions(options);
    //创建扩展
    this.createExtensionManager();
    this.createCommandManager();
    //创建约束
    this.createSchema();
    this.on("beforeCreate", this.options.onBeforeCreate);
    this.emit("beforeCreate", { editor: this });
    this.createHistoryManager();
    //创建state
    this.createState();
    this.createSelectorManager();
    this.on("create", this.options.onCreate);
    this.on("update", this.options.onUpdate);
    this.on("transaction", this.options.onTransaction);
    this.on("destroy", this.options.onDestroy);
    //触发创建事件
    this.emit("create", { editor: this });
  }
  public setOptions(options: Partial<EditorOptions> = {}): void {
    this.options = {
      ...this.options,
      ...options,
    };
  }
  get tr(): Transaction {
    return this.state.tr;
  }
  //初始化state
  private createState(): void {
    const doc = this.options.content(this.schema);
    this.state = PatchState.create({
      plugins: this.extensionManager.plugins,
      schema: this.schema,
      doc: doc,
    });
    this.historyManager.insert(this.state);
  }
  private createCommandManager(): void {
    this.commandManager = new CommandManager({
      editor: this,
    });
  }
  private createSelectorManager(): void {
    this.selectorManager = new SelectorManager(this);
  }

  private createHistoryManager() {
    this.historyManager = new HistoryManager(this.options.historyLimit);
  }
  //初始化插件管理器
  private createExtensionManager(): void {
    const allExtensions = [...this.options.extensions].filter((extension) => {
      return ["extension", "node", "mark"].includes(extension?.type);
    });
    this.extensionManager = new ExtensionManager(allExtensions, this);
  }
  //初始化schema
  private createSchema(): void {
    this.schema = this.extensionManager.schema;
  }

  public get storage(): Record<string, any> {
    return this.extensionStorage;
  }
  //注册插件
  public registerPlugin(
    plugin: Plugin,
    handlePlugins?: (newPlugin: Plugin, plugins: Plugin[]) => Plugin[],
  ): void {
    const plugins = isFunction(handlePlugins)
      ? handlePlugins(plugin, [...this.state.plugins])
      : [...this.state.plugins, plugin];
    this.state = this.state.reconfigure({ plugins });
  }

  //移除插件
  public unregisterPlugin(nameOrPluginKey: string | PluginKey): void {
    const name = typeof nameOrPluginKey === "string"
      ? `${nameOrPluginKey}$`
      : nameOrPluginKey.key;

    this.state = this.state.reconfigure({
      plugins: this.state.plugins.filter((plugin) =>
        !plugin.key.startsWith(name)
      ),
    });
  }
  //销毁编辑器
  public destroy(): void {
    this.emit("destroy");
    this.removeAllListeners();
  }
  //更新状态
  public updateState(transaction: Transaction) {
    this.state = this.state.apply(transaction);
  }
  //资源调度
  public dispatch(transaction: Transaction) {
    this.updateState(transaction);
    if (!transaction.docChanged || transaction.getMeta("preventUpdate")) {
      return;
    }
    this.historyManager.insert(this.state);
    this.emit("update", {
      editor: this,
      transaction,
    });
  }
  //命令集合
  public get commands(): SingleCommands {
    return this.commandManager.commands;
  }
  //查询集合
  public get selectors(): SingleSelectors {
    return this.selectorManager.selectors;
  }
  //历史记录
  get history(): History {
    return this.historyManager.history;
  }
  //回滚到上一步
  undo() {
    this.historyManager.jump(-1);
    this.state = this.historyManager.history.present!;
  }
  //重做
  redo() {
    this.historyManager.jump(1);
    this.state = this.historyManager.history.present!;
  }
  public getAttributes(
    nameOrType: string | NodeType | MarkType,
  ): Record<string, any> {
    return getAttributes(this.state, nameOrType);
  }
  public getJSON(): JSONContent {
    return this.state.doc.toJSON();
  }
}
